
package at.fhj.itm.generator.postgres;

import at.fhj.itm.generator.ColumnValueMapping;
import at.fhj.itm.generator.ColumnValuePair;
import at.fhj.itm.generator.SqlCodeGenerationException;
import at.fhj.itm.generator.SqlCodeGenerator;
import at.fhj.itm.metadata.Column;
import at.fhj.itm.metadata.Constraint;

import at.fhj.itm.metadata.Index;
import at.fhj.itm.metadata.Procedure;
import at.fhj.itm.metadata.Schema;
import at.fhj.itm.metadata.Sequence;
import at.fhj.itm.metadata.Table;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;


import org.apache.velocity.app.VelocityEngine;

/**
 *
 * @author Seuchter
 */
public class PostgresSqlCodeGenerator implements SqlCodeGenerator
{

    private VelocityEngine engine;

    
    public PostgresSqlCodeGenerator(VelocityEngine engine){
    	this.engine = engine;
    }
    
    public PostgresSqlCodeGenerator()
    {
        try
        {
            engine = new VelocityEngine();
            engine.init();
            //tableTemplate = engine.getTemplate("./template/postgres-template-test.vsl");

        } catch (Exception ex)
        {
            throw new SqlCodeGenerationException("Error initializing code generator", ex);
        }


    }

    public String getSqlDialect()
    {
        return "postgres";
    }

    public String generateSchema(Schema schema)
    {
        try
        {
            return PostgresVelocityUtil.callVelocityMacro(engine, "generateTables",
                    "tables", schema.getTables());
        } catch (Exception ex)
        {
            throw new SqlCodeGenerationException("Error genating table sql.", ex);
        }
    }

    public String generateTable(Table table)
    {
        try
        {
            return PostgresVelocityUtil.callVelocityMacro(engine, "generateTable", "table", table);
        } catch (IOException ex)
        {
            throw new SqlCodeGenerationException("Error generating table",ex);
        }
    }
    public String generateSequence(Sequence seq){
         try
        {
            return PostgresVelocityUtil.callVelocityMacro(engine, "generateSequence", "seq", seq);
        } catch (IOException ex)
        {
            throw new SqlCodeGenerationException("Error generating table",ex);
        }
    }
    public String generateProcedure(Procedure proc){
        try{
            return PostgresVelocityUtil.callVelocityMacro(engine, "generateProcedure", "proc", proc);
        }catch(IOException ex){
            throw new SqlCodeGenerationException("Error generating procedure",ex);
        }
    }
    public String generateColumn(Column column)
    {
        try
        {

            return PostgresVelocityUtil.callVelocityMacro(engine,
                    "generateColumnDefinition", "column", column);
        } catch (Exception ex)
        {
            throw new SqlCodeGenerationException("Error generating column");
        }
    }
    public String generateForeignKeyConstraints(List<? extends Table> tables){
        try{
            StringBuilder sb = new StringBuilder();

             String code =  PostgresVelocityUtil.callVelocityMacro(engine, "generateForeignKeyConstraints",
                        "tables",tables);
            sb.append(code);
            return sb.toString();


        }catch(Exception ex){
            throw new SqlCodeGenerationException("Error generating constraints");
        }

    }
    public String generateIndex(Index index)
    {
        try
        {

            return PostgresVelocityUtil.callVelocityMacro(engine,
                    "generateIndex", "index", index);
        } catch (Exception ex)
        {
            throw new SqlCodeGenerationException("Error generating index");
        }

       
    }

    public String generateConstraint(Constraint constraint)
    {
        try
        {

            return PostgresVelocityUtil.callVelocityMacro(engine,
                    "generateConstraint", "constraint", constraint);
        } catch (Exception ex)
        {
            throw new SqlCodeGenerationException("Error generating column");
        }
    }
    
    protected String generateMapppingValue(ColumnValuePair<Column, String> pair){
    	String value = pair.getValue();
    	
    	if(value == null){
    		return "NULL";
    	}
    	if(!pair.isQuoteValue()){
    		return value;
    	}
    	else{
    		return String.format("'%s'", pair.getValue());
    	}
    	
    	
    }
    
    @Override
    public String generateInsertStatement(Table target,
    	ColumnValueMapping<Column, String> mappings) {
    	StringBuilder sb = new StringBuilder();
    	sb.append("INSERT INTO \"").append(target.getName()).append("\" ");
    	StringBuilder columns = new StringBuilder("(");
    	StringBuilder values = new StringBuilder(" VALUES (");
    	for(Iterator<ColumnValuePair< Column, String>> 
    		iter = mappings.getMapping().iterator(); iter.hasNext();)
    	{
    		
    		ColumnValuePair<Column, String> curPair = iter.next();
    		String value = curPair.getValue();
    		if(value == null){
    			value = "NULL";
    		}
    		
    		columns.append("\"").append(curPair.getColumn().getName()).append("\"");
    		values.append(generateMapppingValue(curPair));
    		
    		
    		if(iter.hasNext()){
    			columns.append(",");
    			values.append(",");
    		}
    		
    		
    	}
    	columns.append(")");
    	values.append(");");
    	sb.append(columns);
    	sb.append(values);
    	return sb.toString();
    }
}
